/*****************************************************************************
 * $LastChangedDate: 2012-10-25 21:35:57 -0400 (Thu, 25 Oct 2012) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   OSG-specific Keyboard class.
 *//*
 * LEGAL:   COPYRIGHT (C) 2009 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#if COMPILE_OSG

#define INPUT_DEVICE_KEYBOARD_OSG_CC 1
#include "base/module.hh"
using namespace base;
#include "gfx/module.hh"
#include "gfx/osg.hh"
using namespace gfx;
#include "view/module.hh"
#include "view/window.hh"  // to register event handler
using namespace view;
#include "input/module.hh"
#include "input/device_keyboard.hh"
#include "input/device_keyboard_osg.hh"

#include <osgGA/GUIEventAdapter>

namespace input {

////////////////////////////////////////////////////////////////////////////////
//////////////////////////  KeyboardDeviceOSG  /////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * ctor/dtor.
 *****************************************************************************/
KeyboardDeviceOSG::KeyboardDeviceOSG( void )
{
ASSERT_RUN_ONCE;
    // NOP
}

KeyboardDeviceOSG::~KeyboardDeviceOSG()
{
    // NOP
}

/*****************************************************************************
 * Enable keyboard device.
 *****************************************************************************/
bool
KeyboardDeviceOSG::EnableDevice( void )
{
BEGIN_ONCE {  // base Device class has logic to call EnableDevice() only once

    // Register handler with OSG Viewer which can be obtained
    // from the Window singleton (in view module).
    GET_WINDOW().OsgRegisterEventHandler( new KeyboardDeviceOSG::HandlerOSG );

} END_ONCE

    return true;
}

/*****************************************************************************
 * Handles keyboard events sent from OSG.
 *****************************************************************************/
bool
KeyboardDeviceOSG::HandlerOSG::handle( const osgGA::GUIEventAdapter& eventOSG, osgGA::GUIActionAdapter& )
{
    // Note: OSG events are indicated by bits.

    // Also enqueue key release/up.
    if ( eventOSG.getEventType() & (osgGA::GUIEventAdapter::KEYDOWN
                                   |osgGA::GUIEventAdapter::KEYUP) )
    {
        // Translate OSG event to Keyboard::Event struct (don't confuse event structs).
        KeyboardEvent keyboardEvent;
        keyboardEvent.mKey   = eventOSG.getKey();
        keyboardEvent.mPress = BOOL_CAST(eventOSG.getEventType()  &  osgGA::GUIEventAdapter::KEYDOWN);
        keyboardEvent.mShift = BOOL_CAST(eventOSG.getModKeyMask() &  osgGA::GUIEventAdapter::MODKEY_SHIFT);
        keyboardEvent.mCtrl  = BOOL_CAST(eventOSG.getModKeyMask() &  osgGA::GUIEventAdapter::MODKEY_CTRL);
        keyboardEvent.mAlt   = BOOL_CAST(eventOSG.getModKeyMask() & (osgGA::GUIEventAdapter::MODKEY_ALT
                                                                    |osgGA::GUIEventAdapter::MODKEY_META
                                                                    |osgGA::GUIEventAdapter::MODKEY_SUPER));  // Apple Cmd or Win key

        // OSG remaps Ctrl+letter as {1,..,26}.  Remap to {'a',..,'z'}.
        if ( keyboardEvent.mCtrl )
        {
            if ( (keyboardEvent.mKey >= 1) and (keyboardEvent.mKey <= 26) )
            {
                keyboardEvent.mKey += 96;
            }
        }

        // Enqueue event.
        GET_KEYBOARD_DEVICE().Enqueue( keyboardEvent );

        return true;
    }
    else
    {
        return false;
    }
}

#if OSG_VERSION_LESS_THAN(3,0,0)
void
KeyboardDeviceOSG::HandlerOSG::accept( osgGA::GUIEventHandlerVisitor& v )
{
    v.visit( *this );
}
#endif

} // namespace input

#endif // COMPILE_OSG
